#include "assert.h"
#include "error.h"
#include "lock.h"
#include "mmu.h"
#include "proc.h"
#include "stdio.h"
#include "string.h"
#include "type.h"
#include "utils.h"

#include "fs/deffs.h"
#include "fs/dirent.h"
#include "fs/disk.h"
#include "fs/file.h"
#include "fs/fs.h"
#include "fs/inode.h"
#include "fs/iobuf.h"
#include "fs/stat.h"
#include "fs/vfs.h"

#include "fs/fat32.h"

#include "dbg.h"

#define OFF_IN_FAT32(clus) ((clus) << 2)

const char illegal[] = {'\"', '*', ':', '<', '>', '?', '\\', '|', '\0'};
bool is_shift = FALSE;

fat32FS_t fat32;
// fs_t fat32_fs;

struct entryCache_t {
    // semaphore_t dentry_lk;
    spinlock_t dentry_lk;
    dirent_t dentries[ENTRY_CACHE_NUM];
} pathCache;

dirent_t root;

/**
 * @brief 计算出clus对应簇的起始扇区号
 *
 * @param clus
 * @return uint32_t
 */
static inline uint32_t
firstClusSec(uint32_t clus) {
    return (clus - 2) * fat32.bpb.secPerCluster + fat32.firstDataSec;
}

static inline uint32_t
fatTable_read(uint32_t clus) {
    if (clus >= FAT32_EOC)
        return clus;
    if (clus > fat32.dataClusNum)
        return 0;
    //如果fatTable中，clus对应项尚未读取，此时进行读取
    //不单读取clus对应的fat项，而将clus对应fat项所在扇区全部读取
    if (fat32.fatTable[clus] == 0) {
        // clus对应fat项所在扇区号
        int sec = OFF_IN_FAT32(clus) / fat32.bpb.bytesPerSector + fat32.bpb.reservedSectorNum;
        // sec扇区中，第一个fat项对应的clus编号
        // fat32.bpb.bytesPerSector >> 2 为一个扇区中的fat项数
        int off = (OFF_IN_FAT32(clus) / fat32.bpb.bytesPerSector) * (fat32.bpb.bytesPerSector >> 2);
        disk_read((uint8_t*)(fat32.fatTable + off), sec);
    }
    return fat32.fatTable[clus];
}

int
fatTable_write(uint32_t clus, uint32_t content) {
    if (clus > fat32.dataClusNum)
        return -1;
    uint32_t fatSec = firstClusSec(clus);
    fat32.fatTable[clus] = content;  // TODO
    disk_write((uint8_t*)(fat32.fatTable + clus / fat32.fatEntryPerSec), fatSec);
    return 0;
}

void
clus_zero(uint32_t clus) {
    uint32_t sec = firstClusSec(clus);
    byte_t buf[BSIZE] = {0};
    for (int i = 0; i < fat32.bpb.secPerCluster; ++i, ++sec)
        disk_write(buf, sec);
}

int
clus_alloc(uint8_t dev) {
    for (int i = 0; i < fat32.bpb.secPerFAT32; ++i)  // TODO 如何不从头开始找
        if (fatTable_read(i) == 0) {                 // TODO
            fatTable_write(i, 0xffffffff);
            return i;
        }
    return -E_NO_MEM;
}

int
clus_free(uint32_t clus) {
    return fatTable_write(clus, 0);
}

/**
 * @brief 簇层面读写。读/写clu簇的第off/bytePerSec扇区从off%bytePerSec字节开始的len个字节
 *
 * @param clus
 * @param write
 * @param user
 * @param data
 * @param off
 * @param len
 * @return uint32_t
 */
uint32_t
clus_io(uint32_t clus, bool write, int user, byte_t* data, uint32_t off, uint32_t len) {
    if (off + len > fat32.bytePerClus)  //?不支持超过一簇的读写
        panic("offset out of range");
    uint32_t sec = firstClusSec(clus) + off / fat32.bpb.bytesPerSector;
    off %= fat32.bpb.bytesPerSector;

    byte_t buf[BSIZE];
    address_t temp_addr = (address_t)kvm_trans((address_t)&buf, getCurrentProc()->kpageTable);  // TODO 转换是必要的吗
    uint32_t current = 0;
    for (; current < len; ++sec) {
        disk_read((uint8_t*)temp_addr, sec);

        uint32_t _len = __MIN(len - current, fat32.bpb.bytesPerSector - off);
        if (write) {
            memmove((void*)(buf + off), data, _len);
            disk_write((uint8_t*)temp_addr, sec);
        } else
            memmove(data, (void*)(buf + off), _len);

        off = (off + _len) % fat32.bpb.bytesPerSector;
        current += _len;
    }
    return current;
}

/**
 * @brief 找到文件偏移off的簇，记录到dir中
 *
 * @param dir
 * @param off
 * @param alloc
 * @return uint32_t off在dir->curClus的偏移字节数
 */
int
clus_locate(dirent_t* dir, uint32_t off, bool alloc) {
    uint32_t clusNo = off / fat32.bytePerClus;  //相对于dir开始簇，是第几簇
    if (clusNo < dir->clusCnt) {                //从头开始找
        dir->curClus = dir->firstClus;
        dir->clusCnt = 0;
    }
    while (clusNo > dir->clusCnt) {
        uint32_t clus = fatTable_read(dir->curClus);
        if (clus >= FAT32_EOC) {
            if (alloc) {
                clus = clus_alloc(dir->dev);
                fatTable_write(dir->curClus, clus);
                dir->size += fat32.bytePerClus;
            } else {
                dir->curClus = dir->firstClus;
                dir->clusCnt = 0;
                return -1;
            }
        }
        dir->curClus = clus;
        ++dir->clusCnt;
    }

    return off % fat32.bytePerClus;
}

/**
 * @brief 去除name中的空格和'.'，并判断是否有非法字符
 *
 * @param name
 * @return char*
 */
char*
formatName(char* name) {
    while (*name == ' ' || *name == '.')
        ++name;
    char* p = name;
    for (; *p != '\0'; ++p) {
        if (*p < 0x20 || (strchr(illegal, *p) != NULL))  // 0x20之前在ASCII中为控制字符
            return NULL;
    }
    while (p > name && *p == ' ')
        --p;
    *(p + 1) = '\0';
    return name;
}

//格式 NAME    EXT
void
generateShortName(char* shortName, char* name) {
    int j = 0;
    int len = strlen(name) - 1;
    int k;
    char c;
    for (k = len; k >= 0; --k)
        if (name[k] == '.')
            break;

    if (k < 0) {  //没有'.'
        for (int i = 0; i < 8; ++i) {
            c = name[i];
            if (c == ' ')
                continue;
            else if (c >= 'a' && c <= 'z')
                c += 'A' - 'a';
            else if (strchr(illegal, c) != NULL)
                c = '_';
            shortName[j++] = c;
        }
        memset(shortName + 8, ' ', 3);
    } else {  //有'.'
        for (int i = 0; i < k && j < 8; ++i) {
            char c = name[i];
            if (c == ' ')
                continue;
            else if (c >= 'a' && c <= 'z')
                c += 'A' - 'a';
            else if (strchr(illegal, c) != NULL)
                c = '_';
            shortName[j++] = c;
        }
        uint32_t temp = __MAX(SHORT_NAME_LEN - (len - k), 8);
        memset(shortName + temp, ' ', temp - j);
        j = temp;
        for (int i = k + 1; i < len && j < SHORT_NAME_LEN; ++i) {
            char c = name[i];
            if (c == ' ')
                continue;
            else if (c >= 'a' && c <= 'z')
                c += 'A' - 'a';
            else if (strchr(illegal, c) != NULL)
                c = '_';
            shortName[j++] = c;
        }
    }
    shortName[SHORT_NAME_LEN] = '\0';
}

uint8_t
calCheckSum(uint8_t* shortName) {
    uint8_t sum = 0;
    for (int i = 0; i < SHORT_NAME_LEN; ++i)
        sum = (sum & 1) ? 0x80 : 0 + (sum >> 1) + shortName[i];
    return sum;
}

/**
 * @brief 获取两个 '/' 之间的文件名, 保存到name中
 *
 * @param path 路径，结束后指向路径中的下一个 '/'
 * @param name 记录路径中两个 '/' 之间的文件名
 * @return char*
 */
char*
skipElem(char* path, char* name) {
    // skip '/'
    while (*path == '/')
        ++path;
    if (*path == '\0')
        return NULL;

    char* s = path;
    while (*path != '/' && *path != '\0')
        ++path;
    int len = path - s;
    if (len > FAT32_MAX_FILENAME)
        len = FAT32_MAX_FILENAME;
    name[len] = '\0';
    memmove(name, s, len);
    while (*path == '/')
        ++path;
    return path;
}

void
dentry_lock(dirent_t* dentry) {
    if (dentry == NULL || dentry->ref < 1) {
        printf("dentry lock\n");
        return;
    }
    spinlock_acquire(&dentry->d_lk);
}

void
dentry_unlock(dirent_t* dentry) {
    if (dentry == NULL || dentry->ref < 1) {
        printf("dentry unlock\n");
    }
    spinlock_release(&dentry->d_lk);
}

/**
 * @brief caller need to hold lock of pathCache
 *
 * @return dirent_t*
 */
dirent_t*
pathCache_alloc(dirent_t* parent) {
    dirent_t* dir;
    //从root.next往后越来越不常用，所以从root.prev向前找，实现LRU
    for (dir = root.prev; dir != &root; dir = dir->prev)
        if (dir->ref == 0) {
            dir->ref = 1;
            dir->dev = parent->dev;
            dir->d_off = 0;
            dir->valid = FALSE;
            dir->dirty = FALSE;
            dir->d_type = 0;
            return dir;
        }
    return NULL;
}

/**
 * @brief 文件层面读
 *
 * @param dir
 * @param user
 * @param dst
 * @param off
 * @param len
 * @return int
 */
int
__fat32_read(dirent_t* dir, int user, void* dst, uint32_t off, size_t* len) {
    if ((off > dir->size) || (dir->d_type & ATTR_DIRECTORY))
        return -E_INVAL;

    uint32_t total = 0;
    uint32_t lenTemp = *len;
    *len = 0;
    for (; dir->curClus < FAT32_EOC && total < lenTemp;) {
        if (clus_locate(dir, off, 0) < 0)
            return -E_TOO_BIG;
        uint32_t _len = __MIN(fat32.bytePerClus - off % fat32.bytePerClus, lenTemp - total);
        clus_io(dir->curClus, FALSE, user, dst + total, off % fat32.bytePerClus, _len);
        // if (readLen < _len)
        //     break;
        total += _len;
        off += _len;
    }
    *len = total;
    return total;
}

/**
 * @brief 文件层面写
 *
 * @param dir
 * @param user
 * @param src
 * @param off
 * @param len
 * @return int
 */
int
__fat32_write(dirent_t* dir, int user, void* src, uint32_t off, size_t* len) {
    if ((off > dir->size) || (dir->d_type & ATTR_READ_ONLY))
        return -E_INVAL;
    if (dir->firstClus == 0) {
        dir->curClus = dir->firstClus = clus_alloc(dir->dev);
        dir->clusCnt = 0;
        dir->dirty = 1;
    }

    uint32_t total, _len = 0;
    for (total = 0; total < *len;) {
        clus_locate(dir, off, TRUE);
        _len = __MIN(fat32.bytePerClus - off % fat32.bytePerClus, *len - total);
        clus_io(dir->curClus, TRUE, user, src + total, off, _len);
        off += _len;
        total += _len;
    }
    if ((*len > 0) && (off > dir->size)) {
        dir->size = off;  // TODO什么意思
        dir->dirty = TRUE;
    }
    *len = total;
    return 0;
}

/**
 * @brief 从pathCache中获取parent目录下name的项，如果没找到，从pathCache分配一个可用项
 *
 * @param parent
 * @param name
 * @return dirent_t*
 */
dirent_t*
__fat32_getDirEntry(dirent_t* parent, char* name) {
    dirent_t* dir;
    spinlock_acquire(&pathCache.dentry_lk);

    if (name != NULL) {
        for (dir = root.next; dir != &root; dir = dir->next)
            if (dir->valid && (dir->parent == parent) && (strncmp(dir->d_name, name, FAT32_MAX_FILENAME) == 0)) {
                if (dir->ref == 0)
                    ++dir->parent->ref;
                ++dir->ref;  // TODO作用？
                goto out;
            }
    }

    dir = pathCache_alloc(parent);

out:
    spinlock_release(&pathCache.dentry_lk);
    return dir;
}

dirent_t*
__fat32_dup(dirent_t* dentry) {
    if (dentry != NULL) {
        spinlock_acquire(&pathCache.dentry_lk);
        ++dentry->ref;
        spinlock_release(&pathCache.dentry_lk);
    }
    return dentry;
}

int
__fat32_trunc(dirent_t* dentry) {
    for (uint32_t clus = dentry->firstClus; clus > 1 && clus < FAT32_EOC;) {
        uint32_t next = fatTable_read(clus);
        clus_free(clus);
        clus = next;
    }
    dentry->size = 0;
    dentry->firstClus = 0;
    dentry->dirty = TRUE;
    return 0;  // TODO
}

int
__fat32_fsync(dirent_t* dentry) {
    if (dentry->dirty == FALSE || dentry->valid != TRUE)
        return 0;  // TODO
    uint32_t entCnt;
    uint32_t off = clus_locate(dentry->parent, dentry->d_off, FALSE);
    clus_io(dentry->parent->curClus, FALSE, 0, (byte_t*)&entCnt, off, 1);
    entCnt &= ~LAST_LONG_ENTRY;  // TODO 什么意思
    off = clus_locate(dentry->parent, dentry->d_off + entCnt * sizeof(fat32Entry_t), 0);

    fat32Entry_t fentry;
    clus_io(dentry->parent->curClus, 0, 0, (byte_t*)&fentry, off, sizeof(fentry));
    fentry.shortNameDir.start_high = (uint16_t)(dentry->firstClus >> 16);
    fentry.shortNameDir.start_low = (uint16_t)(dentry->firstClus & 0xffff);
    fentry.shortNameDir.size = dentry->size;
    clus_io(dentry->parent->curClus, TRUE, 0, (byte_t*)&fentry, off, sizeof(fentry));
    return 0;
}

int
__fat32_remove(dirent_t* dentry) {
    if (dentry->valid != TRUE)
        return 0;  // TODO
    uint32_t entCnt = 0;
    uint32_t off = dentry->d_off;  // off记录的是什么偏移
    uint32_t diskOff = clus_locate(dentry->parent, off, FALSE);
    clus_io(dentry->parent->curClus, FALSE, 0, (byte_t*)&entCnt, diskOff, 1);
    entCnt &= ~LAST_LONG_ENTRY;
    uint8_t flag = EMPTY_ENTRY;
    for (int i = 0; i <= entCnt; ++i) {
        clus_io(dentry->parent->curClus, TRUE, 0, (byte_t*)&flag, diskOff, 1);
        off += 32;
        diskOff = clus_locate(dentry->parent, off, FALSE);
    }
    dentry->valid = ERROR;
    return 0;  // TODO
}

int
__fat32_fstat(dirent_t* dentry, stat_t* status) {
    memset(status, 0, sizeof(stat_t));
    // strncpy(status->name, dentry->d_name, STAT_MAX_NAME);
    status->st_mode = (dentry->d_type & ATTR_DIRECTORY) ? S_IFDIR : S_IFREG;
    status->st_dev = dentry->dev;
    status->st_size = dentry->size;
    return 0;  // TODO
}

int
__fat32_readEntryName(char* buf, fat32Entry_t* fentry) {
    if (fentry->longNameDir.attribute == ATTR_LONG_FILE_NAME) {
        wchar_t* name = fentry->longNameDir.f5Name;
        for (int i = 0; i < LONG_NAME_LEN; ++i) {
            buf[i] = *name;
            ++name;
            if (i == 5 - 1)
                name = fentry->longNameDir.m6Name;
            else if (i == 11 - 1)
                name = fentry->longNameDir.e2Name;
        }
    } else {
        int i;
        for (i = 0; fentry->shortNameDir.name[i] != ' ' && i < 8; ++i)
            buf[i] = fentry->shortNameDir.name[i];
        if (fentry->shortNameDir.name[8] != ' ')
            buf[i++] = '.';
        for (int j = 8; j < SHORT_NAME_LEN; ++j, ++i) {
            if (fentry->shortNameDir.name[j] == ' ')
                continue;
            buf[i] = fentry->shortNameDir.name[j];
        }
    }
    return 0;  // TODO
}

int
__fat32_readEntryInfo(dirent_t* dentry, fat32Entry_t* fentry) {
    dentry->d_type = fentry->shortNameDir.attribute;
    dentry->size = fentry->shortNameDir.size;
    dentry->firstClus = ((uint32_t)(fentry->shortNameDir.start_high) << 16) | ((uint32_t)(fentry->shortNameDir.start_low));
    dentry->curClus = dentry->firstClus;
    dentry->clusCnt = 0;
    return 0;  // TODO
}

/**
 * @brief 从dentry的off字节偏移处，获取一个目录项，为空 - type=0, 或长/短目录项
 *
 * @param dentry
 * @param tentry
 * @param off
 * @param count 记录项数
 * @return int
 */
int
__fat32_enExt(dirent_t* dentry, dirent_t* tentry, uint32_t off, int* count) {  // TODO
    if (!(dentry->d_type & ATTR_DIRECTORY))
        panic("__fat32_enExt not dir");
    if (tentry->valid == TRUE)
        panic("__fat32_enExt target valid");
    if (off % 32 != 0)
        panic("__fat32_enExt offset not align");
    if (dentry->valid != TRUE)
        return -E_INVAL;

    fat32Entry_t fentry;
    int cnt = 0;
    memset(tentry->d_name, 0, FAT32_MAX_FILENAME);
    for (int diskOff = clus_locate(dentry, off, FALSE); diskOff >= 0;) {
        uint32_t len = clus_io(dentry->curClus, FALSE, 0, (byte_t*)&fentry, diskOff, sizeof(fentry));
        if (len != sizeof(fentry))
            return -1;  // TODO
        if (fentry.longNameDir.sequence == EMPTY_ENTRY) {
            ++cnt;
            continue;
        } else if (cnt != 0) {  //寻找连续空目录项的最后一项
            *count = cnt;
            return 0;
        }

        if (fentry.longNameDir.attribute == ATTR_LONG_FILE_NAME) {
            int seq = fentry.longNameDir.sequence & ~LAST_LONG_ENTRY;
            if (fentry.longNameDir.sequence & LAST_LONG_ENTRY) {
                *count = seq + 1;  // seq个长文件名目录项+1个短文件名目录项
                count = NULL;      //停止计数
            }
            __fat32_readEntryName(tentry->d_name + (seq - 1) * LONG_NAME_LEN, &fentry);
        } else {
            if (count != NULL) {
                *count = 1;
                __fat32_readEntryName(tentry->d_name, &fentry);
            }
            __fat32_readEntryInfo(tentry, &fentry);
            return 1;
        }
        off += 32;
        diskOff = clus_locate(dentry, off, FALSE);
    }
    return -1;
}

int
__fat32_put(dirent_t* dentry) {
    spinlock_acquire(&pathCache.dentry_lk);

    if ((dentry != &root) && (dentry->valid) && (dentry->ref == 1)) {
        spinlock_acquire(&dentry->d_lk);

        //将dentry插入到root.next处
        dentry->next->prev = dentry->prev;
        dentry->prev->next = dentry->next;
        dentry->next = root.next;
        root.next->prev = dentry;
        root.next = dentry;

        // spinlock_release(&pathCache.dentry_lk);

        if (dentry->valid == ERROR)  // TODO
            __fat32_trunc(dentry);
        else {
            dentry_lock(dentry->parent);  // TODO! 可能遇到parent的锁已获取过的情况
            __fat32_fsync(dentry);
            dentry_unlock(dentry->parent);
        }

        // spinlock_acquire(&pathCache.dentry_lk);
        --dentry->ref;  // TODO ref到底什么含义
        spinlock_release(&dentry->d_lk);
        spinlock_release(&pathCache.dentry_lk);
        if (dentry->ref == 0)
            __fat32_put(dentry->parent);
        return 0;
    }
    --dentry->ref;
    spinlock_release(&pathCache.dentry_lk);
    return 0;
}

dirent_t*
__fat32_lookupDir(dirent_t* dentry, char* name, uint32_t* offPtr) {
    if (!(dentry->d_type & ATTR_DIRECTORY))
        panic("__fat32_lookup not dir");
    if (dentry->valid != TRUE)
        return NULL;

    if (strncmp(name, ".", FAT32_MAX_FILENAME) == 0)
        return __fat32_dup(dentry);
    else if (strncmp(name, "..", FAT32_MAX_FILENAME) == 0) {
        if (dentry == &root)
            return __fat32_dup(&root);
        else
            return __fat32_dup(dentry->parent);
    }

    dirent_t* tentry = __fat32_getDirEntry(dentry, name);
    if (tentry != NULL && tentry->valid == TRUE)
        return tentry;

    int entCnt = (strlen(name) + LONG_NAME_LEN - 1) / LONG_NAME_LEN;
    int count = 0;
    int type;
    uint32_t __off = 0;
    clus_locate(dentry, 0, FALSE);
    type = __fat32_enExt(dentry, tentry, __off, &count);
    while (type != -1) {
        if (type == 0) {  //空目录项
            if (offPtr != NULL && count >= entCnt) {
                *offPtr = __off;
                offPtr = NULL;
            }
        } else if (strncmp(name, tentry->d_name, FAT32_MAX_FILENAME) == 0) {
            tentry->parent = __fat32_dup(dentry);
            tentry->d_off = __off;
            tentry->valid = TRUE;
            return tentry;
        }
        __off += count * sizeof(fat32Entry_t);
        type = __fat32_enExt(dentry, tentry, __off, &count);
    }
    if (offPtr != NULL)
        *offPtr = __off;
    __fat32_put(tentry);
    return NULL;
}

/**
 * @brief 获取path对应的dirent_t, name不是文件名，而是存储路径最后的文件名
 *
 * @param path
 * @param parent dirent_t是否对应于文件的父目录
 * @param name 存储路径最后的文件名，返回给调用者使用
 * @return dirent_t*
 */
dirent_t*
__fat32_lookupPath(char* path, bool parent, char* name) {
    // assert(getCurrentProc()->fp->pwd->inodeType == inode_type_fat32_info);
    dirent_t *dentry, *next;
    if (*path == '/')
        dentry = __fat32_dup(&root);
    else if (*path != '\0')
        dentry = __fat32_dup(getCurrentProc()->cwd);
    else
        return NULL;

    path = skipElem(path, name);
    while (path != NULL) {
        dentry_lock(dentry);

        if (!(dentry->d_type & ATTR_DIRECTORY)) {
            dentry_unlock(dentry);
            __fat32_put(dentry);
            return NULL;
        }
        if (parent == TRUE && *path == '\0') {
            dentry_unlock(dentry);
            return dentry;
        }

        next = __fat32_lookupDir(dentry, name, 0);
        if (next == NULL) {
            dentry_unlock(dentry);  // TODO dentry的锁似乎已释放
            __fat32_put(dentry);
            return NULL;
        }
        dentry_unlock(dentry);  // TODO dentry的锁似乎已释放
        __fat32_put(dentry);
        dentry = next;
        path = skipElem(path, name);
    }
    if (parent == TRUE) {
        __fat32_put(dentry);
        return NULL;
    }
    return dentry;
}

/**
 * @brief dir为文件夹，在此文件夹中，创建entry对应的文件
 *
 * @param dir
 * @param entry
 * @param off
 * @return int
 */
int
__fat32_create(dirent_t* dir, dirent_t* entry, uint32_t off) {
    if (!(dir->d_type & ATTR_DIRECTORY) || (off % sizeof(fat32Entry_t) != 0))
        return -E_INVAL;
    fat32Entry_t fentry;
    memset(&fentry, 0, sizeof(fat32Dentry_t));
    if (off <= 32) {   // TODO? 具体见__fat32_alloc
        if (off == 0)  //创建 '.' 项
            strncpy(fentry.shortNameDir.name, ".", SHORT_NAME_LEN);
        else  // off==32, 创建 '..' 项
            strncpy(fentry.shortNameDir.name, "..", SHORT_NAME_LEN);
        fentry.shortNameDir.attribute = ATTR_DIRECTORY;  // TODO?
        fentry.shortNameDir.start_high = (uint16_t)(entry->firstClus >> 16);
        fentry.shortNameDir.start_low = (uint16_t)(entry->firstClus & 0xffff);
        fentry.shortNameDir.size = 0;  // TODO?
        off = clus_locate(dir, off, TRUE);
        clus_io(dir->curClus, TRUE, 0, (byte_t*)&fentry, off, sizeof(fentry));
    } else {  //长文件名
        //计算所需目录项数，并向上取整
        int entCnt = (strlen(entry->d_name) + LONG_NAME_LEN - 1) / LONG_NAME_LEN;
        char shortName[SHORT_NAME_LEN + 1] = {'\0'};
        generateShortName(shortName, entry->d_name);  // TODO可行？
        fentry.longNameDir.checksum = calCheckSum((uint8_t*)shortName);
        fentry.longNameDir.attribute = ATTR_LONG_FILE_NAME;
        //倒序排列在目录表中
        for (int i = entCnt; i > 0; --i) {
            fentry.longNameDir.sequence = i;
            if (i == entCnt)  // TODO判断条件没错？
                fentry.longNameDir.sequence |= LAST_LONG_ENTRY;
            char* p = entry->d_name + (i - 1) * LONG_NAME_LEN;
            // file name
            wchar_t* name = fentry.longNameDir.f5Name;
            for (int j = 0; j < LONG_NAME_LEN; ++j) {
                *name = p[j];
                ++name;
                if (j == 5 - 1)
                    name = fentry.longNameDir.m6Name;
                else if (j == 11 - 1)
                    name = fentry.longNameDir.e2Name;
            }
            uint32_t diskOff = clus_locate(dir, off, TRUE);
            clus_io(dir->curClus, TRUE, 0, (byte_t*)&fentry, diskOff, sizeof(fentry));
            off += sizeof(fentry);
        }
        strncpy(fentry.shortNameDir.name, shortName, sizeof(fentry.shortNameDir.name));
        fentry.shortNameDir.attribute = entry->d_type;
        fentry.shortNameDir.start_high = (uint16_t)(entry->firstClus >> 16);
        fentry.shortNameDir.start_low = (uint16_t)(entry->firstClus & 0xffff);
        fentry.shortNameDir.size = entry->size;
        off = clus_locate(dir, off, TRUE);
        clus_io(dir->curClus, TRUE, 0, (byte_t*)&fentry, off, sizeof(fentry));
    }
    return 0;
}

dirent_t*
__fat32_alloc(dirent_t* dentry, char* name, uint32_t attr) {
    if (!(dentry->d_type & ATTR_DIRECTORY))
        panic("not dentry");
    if (dentry->valid == FALSE)
        return NULL;
    name = formatName(name);
    if (name == NULL)
        return NULL;

    uint32_t off = 0;
    dirent_t* entry = __fat32_lookupDir(dentry, name, &off);
    if (entry != NULL)  // entry already exists
        return entry;

    spinlock_acquire(&pathCache.dentry_lk);
    {
        entry = pathCache_alloc(dentry);
        entry->d_type = attr;
        entry->size = 0;
        entry->firstClus = 0;
        entry->parent = __fat32_dup(dentry);
        entry->d_off = off;
        entry->clusCnt = 0;
        entry->curClus = 0;
        strncpy(entry->d_name, name, FAT32_MAX_FILENAME);
        entry->d_name[FAT32_MAX_FILENAME] = '\0';
        if (attr == ATTR_DIRECTORY) {
            entry->curClus = entry->firstClus = clus_alloc(dentry->dev);
            __fat32_create(entry, entry, 0);
            __fat32_create(entry, dentry, sizeof(fat32Entry_t));
        } else
            entry->d_type |= ATTR_ARCHIVE;
        __fat32_create(dentry, entry, off);
        entry->valid = TRUE;
    }
    spinlock_acquire(&entry->d_lk);
    return entry;
}

/**
 * @brief 获得path对应的dirent_t
 *
 * @param path
 * @return dirent_t*
 */
dirent_t*
__fat32_name(char* path) {
    char name[FAT32_MAX_FILENAME + 1];
    return __fat32_lookupPath(path, 0, name);
}

/**
 * @brief 获取文件父目录对应的dirent，并将文件名存储于name中
 *
 * @param path
 * @param name
 * @return dirent_t*
 */
dirent_t*
__fat32_nameParent(char* path, char* name) {
    return __fat32_lookupPath(path, TRUE, name);
}
/*
 int
fat32_open(inode_t* node, uint32_t flags) {  // TODO
    // switch (flags & O_ACCMODE) {
    //     case O_RDONLY:

    //         break;
    //     case O_WRONLY:
    //     case O_RDWR:
    //     default:
    //         return -E_INVAL;
    //         break;
    // }
    return 0;
}

 int
fat32_close(inode_t* node) {
    vop_fsync(node);
}

 int
fat32_read(inode_t* node, iobuf_t* iob) {
    dirent_t* dentry = vop_info(node, fat32);

    spinlock_acquire(&dentry->d_lk);

    size_t _len = iob->io_resid;
    int ret = __fat32_read(dentry, 0, iob->io_base, iob->io_off, &_len);  // TODO
    if (_len != 0)
        iobuf_skip(iob, _len);

    spinlock_release(&dentry->d_lk);
    return ret;
}

 int
fat32_write(inode_t* node, iobuf_t* iob) {
    dirent_t* dentry = vop_info(node, fat32);

    spinlock_acquire(&dentry->d_lk);

    size_t _len = iob->io_resid;
    int ret = __fat32_write(dentry, 0, iob->io_base, iob->io_off, &_len);  // TODO
    if (_len != 0)
        iobuf_skip(iob, _len);

    spinlock_release(&dentry->d_lk);
    return ret;
}

 int
fat32_fstat(inode_t* node, stat_t* stat) {
    return __fat32_fstat(vop_info(node, fat32), stat);
}

 int
fat32_fsync(inode_t* node) {
    return __fat32_fsync(vop_info(node, fat32));
}

int
fat32_nameFile(inode_t* node, iobuf_t* iob) {}
int fat32_getDirEntry(inode_t* node, iobuf_t* iob);
int fat32_reclaim(inode_t* node);
int fat32_getType(inode_t* node, uint32_t* type_store);
int fat32_trySeek(inode_t* node, offset_t pos);
int fat32_truncate(inode_t* node, offset_t len);
int fat32_create(inode_t* node, const char* name, bool excl, inode_t** node_store);
int fat32_lookup(inode_t* node, char* path, inode_t** node_store);
int fat32_ioctl(inode_t* node, int op, void* data);

 const inodeOps_t fat32_node_ops = {
    .vop_magic = VOP_MAGIC,
    .vop_open = fat32_open,
    .vop_close = fat32_close,
    .vop_fstat = fat32_fstat,
    .vop_fsync = fat32_fsync,
    .vop_nameFile = fat32_nameFile,
    .vop_getDirEntry = fat32_getDirEntry,
    .vop_reclaim = fat32_reclaim,
    .vop_getType = fat32_getType,
    .vop_lookup = fat32_lookup,
};

 int
fat32_createInode(dirent_t* dentry, uint32_t ino, inode_t** node_store) {
    inode_t* node = alloc_inode(fat32);
    if (node != NULL) {
        vop_init(node, &fat32_node_ops, &fat32_fs);
        dirent_t* dtemp = vop_info(node, fat32);
        node->inodeInfo.__fat32_info;
    }
}
*/
void
fat32_init() {
    __DEBUG_FUNC_START;
    // fat32 = &fat32_fs.fs_info.__fat32_info;
    disk_read((uint8_t*)&fat32.bpb, 0);
    __DEBUG_OUTPUT("fat32.bpb.SystemID[0]:%d\n", *(fat32.bpb.SystemID));
    if (*(fat32.bpb.SystemID) == '\0') {
        __DEBUG_INFO(another init sector);
        disk_read((uint8_t*)&fat32.bpb, 2048);  // TODO为什么是2048?
        is_shift = TRUE;
    }
    fat32.bpb.SystemID[7] = '\0';
    __DEBUG_OUTPUT("fat32.bpb.SystemID:%s\n", fat32.bpb.SystemID);
    if (strncmp(fat32.bpb.SystemID, "FAT32", 5))
        panic("not FAT32 volume");
    if (fat32.bpb.bytesPerSector != BSIZE)
        panic("fat32.bpb.bytesPerSector!=BSIZE");
    fat32.firstDataSec = fat32.bpb.reservedSectorNum + fat32.bpb.FATNum * fat32.bpb.secPerFAT32;
    fat32.dataSecNum = fat32.bpb.totSecs - fat32.firstDataSec;
    fat32.dataClusNum = fat32.dataSecNum / fat32.bpb.secPerCluster;
    fat32.bytePerClus = fat32.bpb.secPerCluster * fat32.bpb.bytesPerSector;

    // fat32.fatTable = (uint32_t*)kmalloc(fat32.bpb.secPerFAT32 * fat32.bpb.bytesPerSector);
    // fat32.fatTable = (uint32_t*)kmalloc(fat32.dataClusNum * 4);
    fat32.fatEntryPerSec = fat32.bpb.bytesPerSector / sizeof(fat32Entry_t);
    // TODO 初始化时仅置零，需要时再读取硬盘，存入数组
    memset(fat32.fatTable, 0, sizeof(fat32.fatTable));
    //     for (int i = 0; i < fat32.bpb.secPerFAT32; ++i) {
    //     if (i % 1000 == 0)
    //         printf("i: %d\n", i);
    //     disk_read((uint8_t*)(fat32.fatTable + i * fat32.fatEntryPerSec), i + fat32.bpb.reservedSectorNum);
    // }
    spinlock_init(&pathCache.dentry_lk, "pathCache_lk");
    spinlock_init(&root.d_lk, "root_lk");
    root.d_type = ATTR_DIRECTORY | ATTR_SYSTEM;
    root.firstClus = root.curClus = fat32.bpb.rootClusterNo;
    root.valid = TRUE;
    root.dev = 0;
    root.prev = root.next = &root;
    strncpy(root.d_name, "/", FS_MAX_FNAME_LEN);
    for (int i = 0; i < ENTRY_CACHE_NUM; ++i) {
        pathCache.dentries[i].dev = 0;
        pathCache.dentries[i].valid = FALSE;
        pathCache.dentries[i].ref = 0;
        pathCache.dentries[i].parent = NULL;
        pathCache.dentries[i].next = root.next;
        pathCache.dentries[i].prev = &root;
        spinlock_init(&pathCache.dentries[i].d_lk, "dentry");
        root.next->prev = &pathCache.dentries[i];
        root.next = &pathCache.dentries[i];
    }
    // elf_load(getCurrentProc(), "getpid");
    __DEBUG_FUNC_END;
}